package com.ideaaedi.zoo.example.springboot.flowable.sharding.entity.dto;

import com.ideaaedi.zoo.example.springboot.flowable.sharding.entity.tuple.StrObjVar;
import lombok.Data;
import lombok.Getter;
import org.springframework.util.CollectionUtils;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * (non-javadoc)
 *
 * @author <font size = "20" color = "#3CAA3C"><a href="https://gitee.com/JustryDeng">JustryDeng</a></font> <img
 * src="https://gitee.com/JustryDeng/shared-files/raw/master/JustryDeng/avatar.jpg" />
 * @since 1.0.0
 */
@Data
public class VarQueryParam  {
    
    /**
     * 变量名
     */
    private String key;
    
    /**
     * 变量值
     */
    private Object value;
    
    /**
     * 变量值
     */
    private ValueType valueType;
    
    /**
     * 查询（任务）本地类型
     * <pre>
     *    true-本地变量;
     *    false-流程变量;
     *    null-流程变量 + 流程变量;
     * </pre>
     */
    private Boolean taskVar;
    
    /**
     * 快速创建
     */
    public static VarQueryParam of(Boolean taskVar, String name, Object value) {
        Objects.requireNonNull(value, "value cannot be null.");
        VarQueryParam variable = new VarQueryParam();
        variable.setKey(name);
        variable.setValue(value);
        variable.setTaskVar(taskVar);
        if (value instanceof String) {
            variable.setValueType(ValueType.STRING);
        } else if ((value instanceof Short) || (value instanceof Integer) || (value instanceof Long) ) {
            variable.setValueType(ValueType.LONG);
        } else if (value instanceof Double) {
            variable.setValueType(ValueType.DOUBLE);
        } else {
            throw new IllegalArgumentException("un-support var-value type '" + value.getClass().getName() + "'");
        }
        return variable;
    }
    
    /**
     * 快速创建
     */
    public static VarQueryParam of(Boolean taskVar, String name, Object value, ValueType valueType) {
        Objects.requireNonNull(value, "value cannot be null.");
        VarQueryParam variable = new VarQueryParam();
        variable.setKey(name);
        variable.setValue(value);
        variable.setValue(valueType);
        if (valueType != ValueType.STRING && valueType != ValueType.LONG &&  valueType != ValueType.DOUBLE) {
            throw new IllegalArgumentException("un-support var-value type '" + valueType.name() + "'");
        }
        return variable;
    }
    
    /**
     * 快速创建
     *
     * @param taskVar 变量类型
     *                 @see #taskVar
     * @param strObjVarColl 变量名&变量值 集合
     */
    public static Collection<VarQueryParam> ofColl(Boolean taskVar, Collection<StrObjVar> strObjVarColl) {
        if (CollectionUtils.isEmpty(strObjVarColl)) {
            return new ArrayList<>();
        }
        return strObjVarColl.stream()
                .map(x -> VarQueryParam.of(taskVar, x.getKey(), x.getValue()))
                .collect(Collectors.toList());
    }
    
    @Getter
    public enum ValueType {
        /**
         * 当 {@link String#length()} <= 4000时，flowable会将其存为此类型
         * <pre>
         * 注：为什么临界值是4000， 是因为ACT_HI_VARINST的表结构中TEXT_的定义是varchar(4000)
         * </pre>
         */
        STRING("string", "TEXT_"),
        
        /**
         * 当 {@link String#length()} > 4000时，flowable会将其存为此类型
         * <pre>
         * 注：为什么临界值是4000， 是因为ACT_HI_VARINST的表结构中TEXT_的定义是varchar(4000)
         * </pre>
         */
        BIG_STRING("longString", "BYTEARRAY_ID_"),
        
        /**
         * 整数
         */
        LONG("short|integer|long", "LONG_"),
        
        /**
         * 浮点
         */
        DOUBLE("double", "DOUBLE_"),
        
        /**
         * BYTEARRAY_ID_值为ACT_GE_BYTEARRAY表的id
         * <p>
         * 此时， varType一般是serializable
         */
        BYTE(null, "BYTEARRAY_ID_");
        
        /**
         * ACT_HI_VARINST表中var_type列的存储值
         */
        private final String varType;
        
        /** ACT_HI_VARINST表的存储列 */
        private final String column;
    
        ValueType(String varType, String column) {
            this.varType = varType;
            this.column = column;
        }
    }
}
